package com.lmf.juc.ReadWriteLock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 总结锁的演变：
 *
 * （1）无锁：多线程抢夺资源
 * （2）synchronized和ReentrantLock，都是独占，每次只可以一个操作，不能共享
 * （3）ReentrantReadWriteLock，读读可以共享，提升性能，但是不能多人写。缺点：造成死锁（一直读，不能写），读进程不能写，写进程可以读。
 * （4）写锁降级为读锁（一般等级写锁高于读锁）
 */

/**
 * 演示读写锁：ReentrantReadWriteLock类
 */
//资源类
class MyCache {
    //创建map
    Map<String, Object> map = new HashMap<>();

    //创建读写锁
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    //写入数据的方法
    public void put(String string, Object object) {
        try {
            //上锁
            rwLock.writeLock().lock();
            //操作
            System.out.println(Thread.currentThread().getName() + " 正在写操作" + string);
            //暂停一会儿
            TimeUnit.MICROSECONDS.sleep(300);
            //写入数据
            map.put(string, object);
            System.out.println(Thread.currentThread().getName() + " 写完了" + string);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //解锁
            rwLock.writeLock().unlock();
        }
    }

    //读取数据的方法
    public Object get(String string) {
        Object result = null;
        try {
            //上锁
            rwLock.readLock().lock();
            //操作
            System.out.println(Thread.currentThread().getName() + " 正在读操作" + string);
            //暂停一会儿
            TimeUnit.MICROSECONDS.sleep(300);
            //获取数据
            result = map.get(string);
            System.out.println(Thread.currentThread().getName() + " 取完了" + string);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //解锁
            rwLock.readLock().unlock();
            return result;
        }
    }
}

//测试结果
public class ReadWriteLockDemo {
    public static void main(String[] args) throws InterruptedException {
        MyCache myCache = new MyCache();
        //创建线程放数据
        for (int i = 1; i <= 5; i++) {
            final int num = i;
            new Thread(() -> {
                myCache.put(num + "", num + "");
            }, String.valueOf(i)).start();
        }

        TimeUnit.MICROSECONDS.sleep(300);

        //创建线程取数据
        for (int i = 1; i <= 5; i++) {
            final int num = i;
            new Thread(() -> {
                myCache.get(num + "");
            }, String.valueOf(i)).start();
        }
    }
}